#include <stdio.h>
#include "Definitions.h"
#include "Simulator.h"
#include "Outports.h"
#include "Inports.h"
#include "Controllers.h"
#include "Signals.h"
#include "Registers.h"
#include "Tracers.h"
#include "Displays.h"
#include "OutportDynamicList.h"

using namespace std;


Controller_ctrl_paddle* Simulator::controller_ctrl_paddle;

Controller_test_paddle_ctrl* Simulator::controller_test_paddle_ctrl;

OutPort_paddle_paddle_y* Simulator::outPort_paddle_paddle_y;

OutPort_test_paddle_ball_incomming* Simulator::outPort_test_paddle_ball_incomming;

OutPort_test_paddle_ball_y* Simulator::outPort_test_paddle_ball_y;

Register_paddle_location_y* Simulator::register_paddle_location_y;

Signal_paddle_new_location_y* Simulator::signal_paddle_new_location_y;

Signal_paddle_distance_y* Simulator::signal_paddle_distance_y;

Signal_paddle_abs_distance_y* Simulator::signal_paddle_abs_distance_y;

Signal_paddle_sign_distance_y* Simulator::signal_paddle_sign_distance_y;

Display_directiveexpression82* Simulator::display_directiveexpression82;

Display_directiveexpression95* Simulator::display_directiveexpression95;

Display_directiveexpression108* Simulator::display_directiveexpression108;

Int32 Simulator::Cycles;

Int32 Simulator::CurrentCycle;

OutportDynamicList* Simulator::OutportList;

OutportDynamicList* Simulator::SortedOutportList;

void Simulator::Initialize(void)
{
    Simulator::controller_ctrl_paddle = new Controller_ctrl_paddle();
    Simulator::controller_test_paddle_ctrl = new Controller_test_paddle_ctrl();
    Simulator::outPort_paddle_paddle_y = new OutPort_paddle_paddle_y();
    Simulator::outPort_test_paddle_ball_incomming = new OutPort_test_paddle_ball_incomming();
    Simulator::outPort_test_paddle_ball_y = new OutPort_test_paddle_ball_y();
    Simulator::register_paddle_location_y = new Register_paddle_location_y();
    Simulator::signal_paddle_new_location_y = new Signal_paddle_new_location_y();
    Simulator::signal_paddle_distance_y = new Signal_paddle_distance_y();
    Simulator::signal_paddle_abs_distance_y = new Signal_paddle_abs_distance_y();
    Simulator::signal_paddle_sign_distance_y = new Signal_paddle_sign_distance_y();
    Simulator::display_directiveexpression82 = new Display_directiveexpression82();
    Simulator::display_directiveexpression95 = new Display_directiveexpression95();
    Simulator::display_directiveexpression108 = new Display_directiveexpression108();
    Simulator::OutportList = new OutportDynamicList();
    Simulator::SortedOutportList = new OutportDynamicList();

    /* call initializers on the entities in simulation */
    Simulator::controller_ctrl_paddle->Initialize();
    Simulator::controller_test_paddle_ctrl->Initialize();
    Simulator::outPort_paddle_paddle_y->Initialize();
    Simulator::outPort_test_paddle_ball_incomming->Initialize();
    Simulator::outPort_test_paddle_ball_y->Initialize();
    Simulator::register_paddle_location_y->Initialize();
    Simulator::signal_paddle_new_location_y->Initialize();
    Simulator::signal_paddle_distance_y->Initialize();
    Simulator::signal_paddle_abs_distance_y->Initialize();
    Simulator::signal_paddle_sign_distance_y->Initialize();
    Simulator::display_directiveexpression82->Initialize();
    Simulator::display_directiveexpression95->Initialize();
    Simulator::display_directiveexpression108->Initialize();
}

void Simulator::Run(void)
{
    int i = 0;
    IOutport* outport;
    for (
    ; Simulator::CurrentCycle < Simulator::Cycles; 
    )
    {
        /* evaluate controllers */
        Simulator::controller_ctrl_paddle->Evaluate();
        Simulator::controller_test_paddle_ctrl->Evaluate();

      for (i = 0; i < OutportList->size(); i++)
      {
			  outport = Simulator::OutportList->at(i);
			  if (outport->_Color == Color::White)
        {
          Simulator::DfsVisit(&(outport));
        }
      }

      for (i = 0; i < SortedOutportList->size(); i++)
      {
          Simulator::SortedOutportList->at(i)->Evaluate();
      }

        /* evaluate registers */
        Simulator::register_paddle_location_y->Evaluate();

        /* evaluate ipblock inports */

        /* evaluate directives */
        Simulator::display_directiveexpression82->Evaluate();
        Simulator::display_directiveexpression95->Evaluate();
        Simulator::display_directiveexpression108->Evaluate();

        /* run tracers */
#ifdef _MSC_VER

#endif // _MSC_VER

        /* update register values */
        Simulator::register_paddle_location_y->Tick();

        /* prepare for next cycle */
      for (i = 0; i < SortedOutportList->size(); i++)
      {
        SortedOutportList->at(i)->_Color = Color::White;
      }

        Simulator::OutportList->clear();
        Simulator::SortedOutportList->clear();
        Simulator::CurrentCycle = Simulator::CurrentCycle + 1;
    }
}

void Simulator::DfsVisit(IOutport** outport)
{
  int i;
  IOutport* child;
  OutportDynamicList* children = (*outport)->GetDependentOutports();
  (*outport)->_Color = Color::Gray;
  for (i = 0; i < children->size(); i = i + 1)
  {
    child = children->at(i);
    if (child->_Color == Color::White)
    {
      Simulator::DfsVisit(&(child));
    }
    else if(child->_Color == Color::Gray)
    {
      throw new ApplicationException("Signal in combinatorial loop.");
    }
  }
  (*outport)->_Color = Color::Black;
  Simulator::SortedOutportList->push_back(*outport);
}
